package com.xprophet.crs.jpeg.codec;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;

import com.drew.imaging.jpeg.JpegProcessingException;
import com.drew.imaging.jpeg.JpegSegmentReader;
import com.xprophet.crs.jpeg.codec.impl.SnoopDecoderImpl;
import com.xprophet.crs.jpeg.codec.model.Fingerprint;
import com.xprophet.crs.jpeg.codec.model.JPEGInfo;

public abstract class AbstractJPEGDecoder implements IJPEGDecoder {

	static Logger log = Logger.getLogger(AbstractJPEGDecoder.class);
	
	protected JPEGInfo info = null;
	
	protected Fingerprint exif = null;
	
	public boolean parseImage(InputStream is) {
		long t1 = System.currentTimeMillis();
		
		/*
		 * TODO Approach 3: As fast as approach 1 (this is what goes on inside the JpegMetadataReader's readMetadata()
		 * method), this code is handy if you want to look into other Jpeg segments too.
		 */
		JpegSegmentReader reader = null;
		try {
			reader = new JpegSegmentReader(is);
		} catch (JpegProcessingException e) {
			log.error("", e);
			return false;
		}

		byte[] bytes = null;
		int[] c_matrix = new int[QTABLE_MAX_IDX + 1];
		int[] i_matrix = new int[QTABLE_MAX_IDX + 1];
		// QTable0
		bytes = reader.readSegment(JpegSegmentReader.SEGMENT_DQT, 0);
		if (bytes != null && bytes.length == QTABLE_MAX_IDX + 2) {
			for (int i = 0; i <= QTABLE_MAX_IDX; i ++) {
				c_matrix[i] = (int) bytes[i + 1];
			}
		}
		// QTable1
		bytes = reader.readSegment(JpegSegmentReader.SEGMENT_DQT, 1);
		if (bytes != null && bytes.length == QTABLE_MAX_IDX + 2) {
			for (int i = 0; i <= QTABLE_MAX_IDX; i ++) {
				i_matrix[i] = (int) bytes[i + 1];
			}
		}
		
		/*
		 * TODO Approach 4: This approach is the slowest, because it decodes the Jpeg image. Of course you now have a
		 * decoded image to play with. In some instances this will be most appropriate.
		 */
//		JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(is);
//		try {
//			decoder.decodeAsBufferedImage();
//		} catch (ImageFormatException e) {
//			log.error("", e);
//			return false;
//		} catch (IOException e) {
//			log.error("", e);
//			return false;
//		}
//		JPEGDecodeParam param = decoder.getJPEGDecodeParam();
//		int[] c_matrix = param.getQTable(0).getTable();
//		int[] i_matrix = param.getQTable(1).getTable();
		
		long t2 = System.currentTimeMillis();
		log.debug((t2-t1)*.001 + " sec");
		//TODO Only use DQT information here 
		// QTable0: FF DB 00 ... (total 67 bytes)
		// QTable1: FF DB 00 ...
		
		// luminance quantization table (ZigZagged)
		// decode ZigZag algorithm to a 8x8 matrix
		int c_len = (int) Math.sqrt(c_matrix.length);
		int[][] c_matrix_8x8 = ZigZag.decode(c_matrix, c_len, c_len);
		ZigZag.toLine(c_matrix_8x8, c_len, c_matrix);
		
		// chrominance quantization table (ZigZagged)
		int i_len = (int) Math.sqrt(i_matrix.length);
		int[][] i_matrix_8x8 = ZigZag.decode(i_matrix, i_len, i_len);
		ZigZag.toLine(i_matrix_8x8, i_len, i_matrix);
		
		info = new JPEGInfo(c_matrix, i_matrix);
		return true;
	}

	public Fingerprint getExif() {
		return exif;
	}

	public void setExif(Fingerprint exif) {
		this.exif = exif;
	}
	
	public static void main(String[] args) throws IOException {
		File f = new File("C:\\Users\\fudarren\\Pictures\\wallpaper\\3208516_367648212.jpg");
		InputStream is = FileUtils.openInputStream(f);
		IJPEGDecoder codec = new SnoopDecoderImpl(null);
		if (codec.parseImage(is)) {
			log.debug(codec.getEncryptedData());
		}
	}
}
